#!/usr/bin/env python
#

import os
import urllib
import time
import csv

from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

"""Description for a simple application that tests blobstore
and datastore speeds. Does so by using each datastorage solution
to find the average test score for people with a given hair color.
"""


class Person(db.Model):
  """Model class for storing and retrieving people from datastore."""
  hair_color = db.StringProperty(required=True)
  test_score = db.IntegerProperty(required=True)
  data = db.BlobProperty(required=True)


class FilterHandler(webapp.RequestHandler):
  """Serves a static page to test datastore and blobstore speeds."""
  def get(self):
    path = os.path.join(os.path.dirname(__file__), 'filter.html')
    self.response.out.write(template.render(path, {}))


class DatastoreFilterHandler(webapp.RequestHandler):
  """Filters and averages using datastore.
  
  Returns data about the request."""
  def get(self):
      hair_color = self.request.get('hair_color')
      start = time.time()
      people_query = Person.all()
      if hair_color and hair_color.strip() != '':
        people_query = Person.gql('WHERE hair_color = :1', hair_color)
      score = 0;
      count = 0;
      for person in people_query:
        score += person.test_score
        count += 1
      elapsed = time.time() - start
      self.response.out.write("[%s, %s, %s]"
          % (elapsed, count, score / count if count > 0 else 0))


class BlobstoreFilterHandler(webapp.RequestHandler):
  """Filters and averages using blobstore.
  
  Returns data about the request."""
  def get(self):
      color = self.request.get('hair_color')
      start = time.time()
      total_score = 0;
      count = 0;
      for score in getScores(color):
        total_score += score
        count += 1
      elapsed = time.time() - start
      self.response.out.write("[%s, %s, %s]"
          % (elapsed, count, total_score / count if count > 0 else 0))

def getScores(hair_color):
  """Gets a list of scores from blobstore for people with hair_color."""
  blob_info = Blob.get_by_key_name('people.csv').blob_info
  blob_reader = blobstore.BlobReader(blob_info.key())
  scores = []
  blob_reader.readline() # ignore headers
  for line in blob_reader:
     properties = line.split(',')
     if not hair_color or hair_color.strip() == '' or properties[1] == hair_color:
       scores.append(int(properties[2]))
  return scores

# Below are all servlets handling blob uploading


class Blob(db.Model):
  """A Model class to store information about the serialized people blob."""
  blob_info = blobstore.BlobReferenceProperty(required=True)

class GetUploadUrlHandler(webapp.RequestHandler):
  """A servlet to return a one time use upload url.""" 
  def get(self):
      upload_url = blobstore.create_upload_url('/postUpload')
      self.response.out.write(upload_url)


class PostUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
  """A servlet to handle post a blob, post upload."""
  def post(self):
    # Blob must be named 'file' to save its information
    upload_files = self.get_uploads('file')
    blob_info = upload_files[0]
    Blob(key_name=blob_info.filename,
      blob_info=blob_info).put()
    self.redirect('/') # required to send a redirect, so just redirect to root

def main():
  """Attach urls to their respective servlets"""
  application = webapp.WSGIApplication(
      [('/', FilterHandler),
       ('/filterDatastore', DatastoreFilterHandler),
       ('/filterBlobstore', BlobstoreFilterHandler),
       ('/getUploadUrl', GetUploadUrlHandler),
       ('/postUpload', PostUploadHandler)
      ], debug=True)
  run_wsgi_app(application)

if __name__ == '__main__':
  main()
